package liming.ai.code.java_maven.info;

import liming.ai.code.java_maven.tool.ToJsonInterface;
import liming.ai.code.java_maven.tool.XmlParser;
import liming.ai.code.v4.data.FileInfo;
import liming.tool.data.DataObject;
import liming.tool.lock.CodeLock;
import liming.tool.lock.LockAtomicBoolean;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class ModeInfo implements ToJsonInterface {
    @JsonField
    private final String modeName;      // 模块名称
    @JsonField
    private  String groupId;       // 新增：项目坐标
    @JsonField
    private final String artifactId;
    @JsonField
    private String version;
    private ModeInfo parent;      // 父模块引用
    @JsonField
    private final List<DependencyInfo> dependencies;
    @JsonField
    private final List<ModeInfo> children;
    @JsonField
    private final List<JavaInfo> javaInfos;

    ModeInfo(ProjectInfo projectInfo, String groupId, String artifactId, String version){
        modeName = projectInfo.getProjectPath();
        this.groupId = groupId;
        this.artifactId = artifactId;
        this.version = version;
        dependencies = new ArrayList<>();
        children = new ArrayList<>();
        javaInfos = new ArrayList<>();
    }
    public ModeInfo(String modeName, String groupId, String artifactId, String version) {
        this.modeName = modeName;
        this.groupId = groupId;
        this.artifactId = artifactId;
        this.version = version;
        children = new ArrayList<>();
        dependencies = new ArrayList<>();
        javaInfos = new ArrayList<>();
    }

    void setParent(ModeInfo parent) {
        this.parent = parent;
        if(groupId==null||groupId.isEmpty()||"null".equals(groupId))
            groupId = parent.groupId;
        if(version==null||version.isEmpty()||"null".equals(version))
            version = parent.version;
    }

    void addChild(ModeInfo child){
        children.add(child);
        child.setParent(this);
    }
    void addDependency(DependencyInfo dependency){
        dependencies.add(dependency);
    }
    void load(DataObject project) throws Exception {
        loadDependencies(project);
        loadChildren(project);
        loadFiles();
    }

    void loadDependencies(DataObject project) {

        Object dependencies = project.opt("dependencies", DataObject.class, new DataObject()).opt("dependency");
        if (dependencies != null) {
            if (dependencies instanceof Collection) {
                ((Collection) dependencies).forEach(
                        dependency -> {
                            loadDependency(this, ((DataObject) dependency).opt("default"));
                        }
                );
            }
            if (dependencies instanceof DataObject) {
                loadDependency(this, (DataObject) dependencies);
            }
        }
    }
    void loadChildren(DataObject project) throws Exception {
        Object modules = project.opt("modules", DataObject.class, new DataObject()).opt("module");
        if (modules != null) {
            if (modules instanceof DataObject) {
                loadChildren(this, ((DataObject) modules).opt("default"));
            }else loadChildren(this, Collections.singleton(modules.toString()));
        }
    }
    void loadFiles() throws IOException {
        javaInfos.addAll(JavaInfo.loadJavaFiles(this));
    }

    public String getModeName() {
        return modeName;
    }

    public String getGroupId() {
        return groupId;
    }

    public String getArtifactId() {
        return artifactId;
    }

    public String getVersion() {
        return version;
    }

    public String getModePath() {
        if(parent==null)
            return modeName;
        return parent.getModePath() + File.separator + modeName;
    }

    @Override
    public String toString() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("modeName", modeName);
        jsonObject.put("groupId", groupId);
        jsonObject.put("artifactId", artifactId);
        jsonObject.put("version", version);
        jsonObject.put("childrenSize", children.size());
        jsonObject.put("dependenciesSize", dependencies.size());
        jsonObject.put("javaInfosSize", javaInfos.size());
        return new JSONObject().put("modeInfo", jsonObject).toString();
    }

    static void loadDependency(ModeInfo modeInfo, DataObject dependencyObject){
        String groupId = dependencyObject.opt("groupId");
        String artifactId = dependencyObject.opt("artifactId");
        String version = dependencyObject.opt("version");
        DependencyInfo dependencyInfo = new DependencyInfo(groupId, artifactId, version);
        LockAtomicBoolean isLoaded = new LockAtomicBoolean(new CodeLock());
        isLoaded.set(true);
        dependencyObject.keySet().forEach(k -> {
            switch (k.intern()) {
                case "groupId":
                case "artifactId":
                case "version":
                    break;
                case "default":{
                    isLoaded.set(false);
                    List<DataObject> aDefault = dependencyObject.opt("default", List.class, new ArrayList<>());
                    aDefault.forEach(dependency -> loadDependency(modeInfo, dependency));
                }
                    break;
                default:
                    dependencyInfo.put(k, dependencyObject.opt(k));

            }
        });
        if(isLoaded.get())
            modeInfo.addDependency(dependencyInfo);
    }
    static void loadChildren(ModeInfo modeInfo,Collection<String> dependencyObject) throws Exception {
        for (String mode : dependencyObject)
            modeInfo.addChild(loadMode(modeInfo, new File(modeInfo.getModePath(),mode)));
    }

    public static ModeInfo loadMode(ProjectInfo projectInfo) throws Exception{
        String projectPath = projectInfo.getProjectPath();
        System.out.println("loadMode:"+ projectPath);
        DataObject project = DataObject.valueOfMap(
                XmlParser.parseXml(new File(projectPath, "pom.xml"))
        ).opt("project", DataObject.class, new DataObject());

        ModeInfo modeInfo = new ModeInfo(new File(projectPath).getName(), project.opt("groupId"), project.opt("artifactId"), project.opt("version")){
            @Override
            public String getModePath() {
                return projectPath;
            }
        };
        modeInfo.load(project);
        return modeInfo;
    }

    public static ModeInfo loadMode(ModeInfo parent,File modeName) throws Exception {
        System.out.println("loadMode:"+modeName);
        DataObject project = DataObject.valueOfMap(
                XmlParser.parseXml(new File(modeName, "pom.xml"))
        ).opt("project", DataObject.class, new DataObject());
        ModeInfo modeInfo = new ModeInfo(modeName.getName(), project.opt("groupId"), project.opt("artifactId"), project.opt("version"));
        modeInfo.setParent(parent);
        modeInfo.load(project);
        return modeInfo;
    }
}
